#pragma once

#include <AVUIItemStructList.h>

namespace AVUI {


/// <summary>Represents a variable size last-in-first-out (LIFO) collection of instances of the same arbitrary type.</summary>
template <class T>
class Stack : public Object
{
public:
#pragma region Public Methods

    /// <summary>Initializes a new instance of the <see cref="T:System.Collections.Generic.Stack`1"></see> class that is empty and has the default initial capacity.</summary>
    Stack() { }

    /// <summary>Initializes a new instance of the <see cref="T:System.Collections.Generic.Stack`1"></see> class that is empty and has the specified initial capacity or the default initial capacity, whichever is greater.</summary>
    /// <param name="capacity">The initial number of elements that the <see cref="T:System.Collections.Generic.Stack`1"></see> can contain.</param>
    /// <exception cref="T:System.ArgumentOutOfRangeException">capacity is less than zero.</exception>
    Stack(int capacity) : m_values(capacity) { }

    /// <summary>Removes all objects from the <see cref="T:System.Collections.Generic.Stack`1"></see>.</summary>
    /// <filterpriority>1</filterpriority>
    void Clear() { m_values.Clear(); }

    /// <summary>Determines whether an element is in the <see cref="T:System.Collections.Generic.Stack`1"></see>.</summary>
    /// <returns>true if item is found in the <see cref="T:System.Collections.Generic.Stack`1"></see>; otherwise, false.</returns>
    /// <param name="item">The object to locate in the <see cref="T:System.Collections.Generic.Stack`1"></see>. The value can be null for reference types.</param>
    bool Contains(const T& item) const { return m_values.Contains(item); }

    /// <summary>Returns the object at the top of the <see cref="T:System.Collections.Generic.Stack`1"></see> without removing it.</summary>
    /// <returns>The object at the top of the <see cref="T:System.Collections.Generic.Stack`1"></see>.</returns>
    /// <exception cref="T:System.InvalidOperationException">The <see cref="T:System.Collections.Generic.Stack`1"></see> is empty.</exception>
    T& Peek() { if(m_values.get_Count() == 0) LibraryCriticalError(); return m_values[m_values.get_Count() - 1]; }

    /// <summary>Removes and returns the object at the top of the <see cref="T:System.Collections.Generic.Stack`1"></see>.</summary>
    /// <returns>The object removed from the top of the <see cref="T:System.Collections.Generic.Stack`1"></see>.</returns>
    /// <exception cref="T:System.InvalidOperationException">The <see cref="T:System.Collections.Generic.Stack`1"></see> is empty.</exception>
    T Pop() { if(m_values.get_Count() == 0) LibraryCriticalError(); T retVal = m_values[m_values.get_Count() - 1]; m_values.RemoveAt(m_values.get_Count() - 1); return retVal; } 

    /// <summary>Inserts an object at the top of the <see cref="T:System.Collections.Generic.Stack`1"></see>.</summary>
    /// <param name="item">The object to push onto the <see cref="T:System.Collections.Generic.Stack`1"></see>. The value can be null for reference types.</param>
    void Push(const T& item) { m_values.AddItem(item); }
#pragma endregion Public Methods

#pragma region Public Properties

    int get_Count() { return m_values.get_Count(); }

#pragma endregion Public Properties

private:
#pragma region Private Fields

    ItemStructList<T> m_values;

#pragma endregion Private Fields

};

};
